// File provided for Microsoft Shared Source.
// Copyright (c) Microsoft Corporation. All rights reserved.

// Implementation of DLL Exports.
#include "stdafx.h"
#include "resource.h"
#include "WMIFldr.h"
#include "dlldatax.h"

#include "CWMIFldr.h"

class CWMIFldrModule : public CAtlDllModuleT< CWMIFldrModule >
{
public :
    DECLARE_LIBID(LIBID_WMIFldrLib)
    DECLARE_REGISTRY_APPID_RESOURCEID(IDR_WMIFLDR, "{317294EB-C6B4-461F-8CCA-FE6F28865465}")
};

LONG g_cDllLock = 0;
CWMIFldrModule _AtlModule;


// DLL Entry Point
extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
    UNREFERENCED_PARAMETER(hInstance);
    return _AtlModule.DllMain(dwReason, lpReserved); 
}

// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void)
{
    return (0 == g_cDllLock ? S_OK : S_FALSE) ;
}

typedef HRESULT (*CREATEFN)(REFGUID riid, void **ppv);

struct CLASS_ENTRY
{
    REFCLSID rclsid;
    CREATEFN createFn;
#pragma warning (suppress: 4510)
#pragma warning (suppress: 4610)
};

template <class T>
HRESULT CreateInstance(REFIID riid, void **ppv)
{
    T *pT = new T();
    HRESULT hr = pT ? S_OK : E_OUTOFMEMORY;
    if (SUCCEEDED(hr))
    {
        hr = pT->QueryInterface(riid, ppv);
    }

    return hr;
}

#define CLS_ENTRY(Class) { __uuidof(Class) , CreateInstance<Class> }
static const CLASS_ENTRY g_rgClasses[] = 
{
    CLS_ENTRY(CWMIFldr),
};

// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv)
{
    HRESULT hr = CLASS_E_CLASSNOTAVAILABLE;
    *ppv = NULL;
    for (size_t i = 0; i < ARRAYSIZE(g_rgClasses); i++)
    {
        if (IsEqualCLSID(g_rgClasses[i].rclsid, rclsid))
        {
            hr = g_rgClasses[i].createFn(riid, ppv);
            break;
        }
    }
    return hr;
}

// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
    // registers object, typelib and all interfaces in typelib
    HRESULT hr = _AtlModule.DllRegisterServer();
    if (SUCCEEDED(hr))
    {
        hr = CWMIFldr::UpdateRegistry(TRUE);
    }
    return hr;
}


// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
    HRESULT hr = _AtlModule.DllUnregisterServer();
    if (SUCCEEDED(hr))
    {
        hr = CWMIFldr::UpdateRegistry(TRUE);
    }
    return hr;
}

static CAtlMap<IID, PCWSTR> g_mapIIDToName;
PCWSTR SmartStringFromIID(REFIID riid)
{
    PCWSTR pszInterface = NULL;
    if (!g_mapIIDToName.Lookup(riid, pszInterface))
    {
        LPOLESTR pszIID = NULL;
        HRESULT hr = StringFromIID(riid, &pszIID);
        if (SUCCEEDED(hr))
        {
            pszInterface = pszIID;

            WCHAR szReg[100];
            WCHAR szInterface[200];
            static const PCWSTR s_rgpszfmt[] = { L"Interface\\%s", L"CLSID\\%s" };

            for (size_t iFmt = 0; iFmt < ARRAYSIZE(s_rgpszfmt); iFmt++)
            {
                hr = StringCchPrintfW(szReg, ARRAYSIZE(szReg), L"Interface\\%s", pszInterface);
                if (SUCCEEDED(hr))
                {
                    HKEY hkeyInterface;
                    if (ERROR_SUCCESS == RegOpenKey(HKEY_CLASSES_ROOT, szReg, &hkeyInterface))
                    {
                        DWORD dwType;
                        DWORD cbData = sizeof(szInterface);
                        if (ERROR_SUCCESS == RegQueryValueEx(hkeyInterface, NULL, NULL, &dwType, (BYTE*)szInterface, &cbData) 
                            && (dwType == REG_SZ
                            || dwType == REG_EXPAND_SZ))
                        {
                            szInterface[ARRAYSIZE(szInterface) - 1] = L'\0';
                            pszInterface = szInterface;
                            break;
                        }
                        RegCloseKey(hkeyInterface);
                    }
                }
            }
            pszInterface = StrDup(pszInterface);
            g_mapIIDToName.SetAt(riid, pszInterface);

            CoTaskMemFree(pszIID);
        }
    }
    return pszInterface;
}

static CAtlMap<PROPERTYKEY, PCWSTR> g_mapPKEYToName;
PCWSTR SmartStringFromPKEY(REFPROPERTYKEY pkey)
{
    PCWSTR pszPKEY = NULL;
    if (!g_mapPKEYToName.Lookup(pkey, pszPKEY))
    {
        PWSTR pszPKEYGen;
        HRESULT hr = PSGetNameFromPropertyKey(pkey, &pszPKEYGen);
        if (FAILED(hr))
        {
            PWSTR pszRaw = (PWSTR)CoTaskMemAlloc(PKEYSTR_MAX * sizeof(*pszRaw));
            if (pszRaw)
            {
                hr = PSStringFromPropertyKey(pkey, pszRaw, PKEYSTR_MAX);
                if (SUCCEEDED(hr))
                {
                    pszPKEYGen = pszRaw;
                    pszRaw = NULL;
                }
                else
                {
                    pszPKEYGen = StrDup(L"");
                    hr = pszPKEYGen ? S_OK : E_OUTOFMEMORY;
                }
                CoTaskMemFree(pszRaw);
            }
            else
            {
                hr = E_OUTOFMEMORY;
            }
        }

        if (SUCCEEDED(hr))
        {
            g_mapPKEYToName.SetAt(pkey, pszPKEYGen);
            pszPKEY = pszPKEYGen;
        }
    }
    return pszPKEY;
}

BOOL ShouldTracePKEY(REFPROPERTYKEY pkey)
{
    BOOL fShouldTrace = TRUE;
    static const PROPERTYKEY s_rgPKEYsToIgnore[] = 
    {
        PKEY_DateModified,
        PKEY_PerceivedType,
        PKEY_FindData,
        PKEY_OfflineAvailability,
        PKEY_OfflineStatus,
    };
    for (size_t iKey = 0; iKey < ARRAYSIZE(s_rgPKEYsToIgnore); iKey++)
    {
        if (IsEqualPropertyKey(s_rgPKEYsToIgnore[iKey], pkey))
        {
            fShouldTrace = FALSE;
            break;
        }
    }
    if (fShouldTrace)
    {
        fShouldTrace++;
    }

    return fShouldTrace;
}

BOOL ShouldTraceIID(REFIID riid)
{
    BOOL fShouldTrace = TRUE;
    static const IID s_rgIIDsToIgnore[] = 
    {
        // Documented, but we don't use them currently - might want the ability to turn these on and off
        // future considerations
        { 0x2ec06c64, 0x1296, 0x4f53, { 0x89, 0xe5, 0xec, 0xce, 0x4e, 0xfc, 0x21, 0x89 } }, // IShellFolder3 - we could do something better here than is done by default
        { 0x7d688a70, 0xc613, 0x11d0, { 0x99, 0x9b, 0x00, 0xc0, 0x4f, 0xd6, 0x55, 0xe1 } }, // IShellIconOverlay - could do the slow overlay sometimes...
        { 0xfc4801a3, 0x2ba9, 0x11cf, { 0xa2, 0x29, 0x00, 0xaa, 0x00, 0x3d, 0x73, 0x52 } }, // IObjectWithSite - not using the site for anything yet :)
        { 0x00000122, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }, // IDropTarget
        { 0xe07010ec, 0xbc17, 0x44c0, { 0x97, 0xb0, 0x46, 0xc7, 0xc9, 0x5b, 0x9e, 0xdc } }, // IExplorerPaneVisibility
        { 0x64961751, 0x0835, 0x43c0, { 0x8f, 0xfe, 0xd5, 0x76, 0x86, 0x53, 0x0e, 0x64 } }, // * IExplorerCommandProvider - definitely going to do this one
        { 0xbc110b6d, 0x57e8, 0x4148, { 0xa9, 0xc6, 0x91, 0x01, 0x5a, 0xb2, 0xf3, 0xa5 } }, // IPropertyStoreFactory - be nice when we're hooking up editing properties depending on if we make properties an item or not
        
        // unlikely to use
        { 0x10df43c8, 0x1dbe, 0x11d3, { 0x8b, 0x34, 0x00, 0x60, 0x97, 0xdf, 0x5b, 0xd4 } }, // IBrowserFrameOptions - we're not doing anything special
        { 0x000214e5, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }, // IShellIcon - we would always have to return S_FALSE anyway, so there's no value in implementing this
        { 0x79eac9ee, 0xbaf9, 0x11ce, { 0x8c, 0x82, 0x00, 0xaa, 0x00, 0x4b, 0xa9, 0x0b } }, // IInternetSecurityManager
        __uuidof(IObjectProvider),                                                          // are the OIDs even public?
        __uuidof(IQueryInfo),                                                               // use a proplist instead
        __uuidof(IPropertyStore),
        __uuidof(IPropertyStoreCache),
        __uuidof(IThumbnailHandlerFactory), 
        __uuidof(IExtractImage), 

        // ??? - not yet understood
        { 0x000214f9, 0x0000, 0x0000, { 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 } }, // IShellLinkW

        // Don't appear to be documented, always filter them
        { 0x321a6a6a, 0xd61f, 0x4bf3, { 0x97, 0xae, 0x14, 0xbe, 0x29, 0x86, 0xbb, 0x36 } }, // IObjectWithBackReferences
        { 0x176c11b1, 0x4302, 0x4164, { 0x84, 0x30, 0xd5, 0xa9, 0xf0, 0xee, 0xac, 0xdb } }, // IFrameLayoutDefinition
        { 0x32ae3a1f, 0xd90e, 0x4417, { 0x9d, 0xd9, 0x23, 0xb0, 0xdf, 0xa4, 0x62, 0x1d } }, // IItemSetOperations
        { 0x38698b65, 0x1ca7, 0x458c, { 0xb4, 0xd6, 0xe0, 0xa5, 0x13, 0x79, 0xc1, 0xd2 } }, // IInfoPaneProvider
        { 0x053b4a86, 0x0dc9, 0x40a3, { 0xb7, 0xed, 0xbc, 0x6a, 0x2e, 0x95, 0x1f, 0x48 } }, // IFolderType
        { 0x93f81976, 0x6a0d, 0x42c3, { 0x94, 0xdd, 0xaa, 0x25, 0x8a, 0x15, 0x54, 0x70 } }, // {93F81976-6A0D-42C3-94DD-AA258A155470}
        { 0x7361ee29, 0x5bad, 0x459d, { 0xa9, 0xf5, 0xf6, 0x55, 0x06, 0x89, 0x82, 0xf0 } }, // {7361EE29-5BAD-459D-A9F5-F655068982F0}
        { 0xb09c4b99, 0xa882, 0x4f63, { 0xbb, 0x41, 0xac, 0x4c, 0x5d, 0xf8, 0x02, 0xc5 } }, // {B09C4B99-A882-4F63-BB41-AC4C5DF802C5}
        { 0x924502a7, 0xcc8e, 0x4f60, { 0xae, 0x1f, 0xf7, 0x0c, 0x0a, 0x2b, 0x7a, 0x7c } }, // {924502A7-CC8E-4f60-AE1F-F70C0A2B7A7C}
    };

    for (size_t iIID = 0; iIID < ARRAYSIZE(s_rgIIDsToIgnore); iIID++)
    {
        if (IsEqualIID(s_rgIIDsToIgnore[iIID], riid))
        {
            fShouldTrace = FALSE;
            break;
        }
    }

    if (fShouldTrace)
    {
        fShouldTrace++;
    }

    return fShouldTrace;
}